package org.teamh.artificialIntelligenceEasy;

import java.util.LinkedList;

import org.teamh.connection.json.command.JsonSender;
import org.teamh.game.repository.MapRepository;
import org.teamh.gui.Event;
import org.teamh.gui.InterfaceManager;
import org.teamh.gui.Screen;
import org.teamh.gui.ingame.IngameScreen;
import org.teamh.gui.loadingscreen.LoadingScreen;
import org.teamh.gui.lobby.LobbyScreen;
import org.teamh.gui.login.LoginScreen;
import org.teamh.gui.mapeditor.MapEditorScreen;
import org.teamh.logic.datamodel.Cell;
import org.teamh.logic.datamodel.Creep;
import org.teamh.logic.datamodel.Tile;
import org.teamh.logic.datamodel.Tower;
import org.teamh.logic.datamodel.User;
import org.teamh.logic.datamodel.UserAssets;
import org.teamh.logic.datamodel.Waypoint;

import de.lessvoid.nifty.Nifty;

/**
 * This class is the base for the AI, and is comparable with the graphical user
 * interface of the client.
 * 
 * @author richard
 * 
 */
public class AIInterfaceManager extends Thread implements InterfaceManager{

	private StartAI startAI;
	
	private String name;
	private String password;
	private String game;
	
	private Tile startTile;
	private User user;
	
	private boolean loggedIn;
	private boolean inGame;
	private boolean gameStarted;
	private LinkedList<LinkedList<Cell>> towerShotSorted = new LinkedList<LinkedList<Cell>>();
	private boolean states[] = new boolean[6];
	private int currentState = 0;
	private int stateInformation[] = {200, 450, 150, 1100, 3200, 7900, 1800};
	private String slow;
	private String speed;
	
	private boolean isRunning;
	
	/**
	 * Creates a new AIInterfaceManager, which logs in, with the specified name
	 * and password into the specified game.
	 * 
	 * @param startAI
	 * @param name
	 * @param password
	 * @param game
	 */
	public AIInterfaceManager(StartAI startAI, String name, String password, String game) {
		this.startAI = startAI;
		this.name = name;
		this.password = password;
		this.game = game;
	}
	
	@Override
	public void run() {
		System.out.println("started ai with: " + name + " and password: " + password);
		
		//log into the game
		login();
		
		//waits, until the player is logged in
		waitForLogin();
		
		//join the game
		joinGame();
		
		//wait, until the game is loaded
		waitForGameLoaded();
		
		//get the user object
		grabUser();
		
		//select a start tile
		selectStartTile();
		
		//wait, until the game is started
		waitForStartGame();
		
		//play the game
		playGame();
		
		//leave the game
		leaveGame();
		
		waits(300);
		
		//remove dependencies
		System.out.println(name + ": closing");
		startAI.exit();
		System.out.println(name + ": closed");
	}
	
	private void waitForLogin() {
		System.out.println(name + ": waits, until it is logged in");
		while(!loggedIn) {
			waits(20);
		}
	}
	
	/**
	 * This methods waits, until the game is loaded. It only waits for 100
	 * seconds. If the game not exists, the AI will exit
	 */
	private void waitForGameLoaded() {
		int i = 0;
		for(; i < 1000 && !startAI.getModel().isManagerReady(); i++) {
			System.out.println(name + ": waits for load game " + i + "/999");
			waits(100);
		}
		if(i == 1000) {
			System.out.println("AI could not join the game");
			System.exit(0);
		}
		startAI.getModel().setManagerReady(false);
		inGame = true;
		System.out.println(name + ": game is loaded");
	}

	/**
	 * This method logs the player into the game
	 */
	private void login() {
		System.out.println(name + ": login");
		startAI.getConnection().sendMessage("login " + name + " " + password);
	}
	
	/**
	 * This methods joins the selected game
	 */
	private void joinGame() {
		System.out.println(name + ": joins the game: " + game);
		startAI.getConnection().sendMessage("join game " + game);
	}
	
	/**
	 * This method leaves the current game
	 */
	private void leaveGame() {
		System.out.println(name + ": leave the game");
		JsonSender.leaveGame();
	}
	
	/**
	 * This method grabs the user name from the user assets of the datamodel. 
	 */
	private void grabUser() {
		System.out.println(name + ": grabs the user");
		for(UserAssets u: startAI.getLogic().getManager().getUserAssets().values()) {
			if(u.getUser() != null && u.getUser().getNickname() != null && u.getUser().getNickname().equals(name)) {
				user = u.getUser();
			}
		}
		
		if(user == null) {
			System.out.println(name + ": could not grab user from game");
			System.out.println(name + ": closes the game");
			System.exit(0);
		}
	}
	
	/**
	 * This method selects a start tile and waits, until the start tile is selected correctly. 
	 */
	private void selectStartTile() {
		do {
			selectRandomStartTile();
		} while(!waitForSelectedStartTile());
	}
	
	/**
	 * With this method, a random start tile is selected. 
	 */
	private void selectRandomStartTile() {
		System.out.println(name + ": chooses a start tile by random");
		
		for(Tile t: startAI.getLogic().getManager().getTiles().values()) {
			if(t.getUserAssets() == null) {
				startTile = t;
				JsonSender.chooseTile(t.getID());
				return;
			}
		}
		
		System.out.println(name + ": there is no empty start tile");
		System.out.println(name + ": closes program");
		System.exit(0);
	}
	
	/**
	 * This method waits, until the start tile is selected. If
	 */
	private boolean waitForSelectedStartTile() {
		System.out.println(name + ": waits for the selection of the start tile");
		for(int i = 0; i < 100; i++) {
			if(startTile.getUserAssets() != null && startTile.getUserAssets().getUser() != null) {
				if(startTile.getUserAssets().getUser() == user) {
					System.out.println(name + ": starttile was selected correctly");
					return true;
				} else {
					System.out.println(name + ": startile was not selected correctly");
					return false;
				}
			}
			waits(20);
		}
		
		return false;
	}
	
	/**
	 * Waits, until the current game is started. 
	 */
	private void waitForStartGame() {
		System.out.println(name + ": waits, until the game started");
		while(!gameStarted) {
			waits(20);
		}
	}
	
	private void sortShotOrder() {
		Waypoint w = user.getUserAssets().getTile().getMap().getEnterWaypoint();
		LinkedList<Cell> cells = new LinkedList<Cell>();

		while (!w.getID().equals(
				user.getUserAssets().getTile().getMap().getExitWaypoint()
						.getID())) {
			if (w.getPrevious() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() - 1,
									w.getPrevious().getCell().getY()) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() - 1,
									w.getPrevious().getCell().getY()).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getPrevious().getCell().getX() - 1,
								w.getPrevious().getCell().getY()));
			}
			if (w.getPrevious() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() + 1,
									w.getPrevious().getCell().getY()) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() + 1,
									w.getPrevious().getCell().getY()).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getPrevious().getCell().getX() + 1,
								w.getPrevious().getCell().getY()));
			}
			if (w.getPrevious() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() - 1,
									w.getPrevious().getCell().getY() - 1) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() - 1,
									w.getPrevious().getCell().getY() - 1)
							.getType().equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getPrevious().getCell().getX() - 1,
								w.getPrevious().getCell().getY() - 1));
			}
			if (w.getPrevious() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() + 1,
									w.getPrevious().getCell().getY() + 1) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getPrevious().getCell().getX() + 1,
									w.getPrevious().getCell().getY() + 1)
							.getType().equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getPrevious().getCell().getX() + 1,
								w.getPrevious().getCell().getY() + 1));
			}

			if (cells.size() > 0) {
				towerShotSorted.add(cells);
			}
			cells = new LinkedList<Cell>();

			if (startAI.getLogic().getManager()
					.getByXandY(w.getCell().getX() - 1, w.getCell().getY()) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getCell().getX() - 1,
									w.getCell().getY()).getType()
							.equals("TOWER")) {
				cells.add(startAI.getLogic().getManager()
						.getByXandY(w.getCell().getX() - 1, w.getCell().getY()));
			}
			if (startAI.getLogic().getManager()
					.getByXandY(w.getCell().getX() + 1, w.getCell().getY()) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getCell().getX() + 1,
									w.getCell().getY()).getType()
							.equals("TOWER")) {
				cells.add(startAI.getLogic().getManager()
						.getByXandY(w.getCell().getX() + 1, w.getCell().getY()));
			}
			if (startAI.getLogic().getManager()
					.getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getCell().getX() - 1,
									w.getCell().getY() - 1).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getCell().getX() - 1,
								w.getCell().getY() - 1));
			}
			if (startAI.getLogic().getManager()
					.getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getCell().getX() + 1,
									w.getCell().getY() + 1).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getCell().getX() + 1,
								w.getCell().getY() + 1));
			}

			if (cells.size() > 0) {
				towerShotSorted.add(cells);
			}
			cells = new LinkedList<Cell>();

			if (w.getNext() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() - 1,
									w.getNext().getCell().getY()) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() - 1,
									w.getNext().getCell().getY()).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getNext().getCell().getX() - 1,
								w.getNext().getCell().getY()));
			}
			if (w.getNext() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() + 1,
									w.getNext().getCell().getY()) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() + 1,
									w.getNext().getCell().getY()).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getNext().getCell().getX() + 1,
								w.getNext().getCell().getY()));
			}
			if (w.getNext() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() - 1,
									w.getNext().getCell().getY() - 1) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() - 1,
									w.getNext().getCell().getY() - 1).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getNext().getCell().getX() - 1,
								w.getNext().getCell().getY() - 1));
			}
			if (w.getNext() != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() + 1,
									w.getNext().getCell().getY() + 1) != null
					&& startAI
							.getLogic()
							.getManager()
							.getByXandY(w.getNext().getCell().getX() + 1,
									w.getNext().getCell().getY() + 1).getType()
							.equals("TOWER")) {
				cells.add(startAI
						.getLogic()
						.getManager()
						.getByXandY(w.getNext().getCell().getX() + 1,
								w.getNext().getCell().getY() + 1));
			}

			if (cells.size() > 0) {
				towerShotSorted.add(cells);
			}
			cells = new LinkedList<Cell>();

			w = w.getNext();
		}
	}
	
	/**
	 * calculates a value for placing a tower
	 */
	private void cellToValue() {
		for (Cell c: user.getUserAssets().getTile().getMap().getCells().values()) {
			if (c.getType().equals("WALKABLE")) {
				
				if (startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY()) != null && startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY()).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY()).setValue(startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY()).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY()) != null && startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY()).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY()).setValue(startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY()).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() - 1) != null && startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() - 1).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() - 1).setValue(startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() - 1).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() + 1) != null && startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() + 1).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() + 1).setValue(startAI.getLogic().getManager().getByXandY(c.getX(), c.getY() + 1).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() + 1) != null && startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() + 1).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() + 1).setValue(startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() + 1).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() - 1) != null && startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() - 1).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() - 1).setValue(startAI.getLogic().getManager().getByXandY(c.getX() + 1, c.getY() - 1).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() + 1) != null && startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() + 1).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() + 1).setValue(startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() + 1).getValue() + 1);
				}
				
				if (startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() - 1) != null && startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() - 1).getType().equals("TOWER")) {
					startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() - 1).setValue(startAI.getLogic().getManager().getByXandY(c.getX() - 1, c.getY() - 1).getValue() + 1);
				}
				
			}
		}	
	}
	
	private String findBestCell() {
		Cell bestCell = new Cell("");
		int index = 0;
		int max = 0;
		
		for(UserAssets u : startAI.getLogic().getManager().getUserAssets().values()) {
			if(!u.getID().equals(user.getUserAssets().getID())) {
				for(Creep cr : u.getCreeps().values()) {
					index = Math.max(cr.getCurrentWaypoint().getIndex(), index);
				}
			}
		}
		
		Waypoint w = user.getUserAssets().getTile().getMap().getWaypointByIndex(index + 3);
		
		while (w.getNext() != null) {
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY()).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY()).getValue() > max && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY()).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY()).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY());
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY()).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY()).getValue() > max  && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY()).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY()).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY());
				}			
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() - 1).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() - 1).getValue() > max && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() - 1).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() - 1).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() - 1);
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() + 1).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() + 1).getValue() > max  && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() + 1).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() + 1).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX(), w.getCell().getY() + 1);
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1).getValue() > max && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() + 1);
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() - 1).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() - 1).getValue() > max && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() - 1).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() - 1).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() + 1, w.getCell().getY() - 1);
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() + 1).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() + 1).getValue() > max && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() + 1).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() + 1).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() + 1);
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1).getType().equals("TOWER")) {
				if (user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1).getValue() > max && user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1).getTower() == null) {
					max = (int)user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1).getValue();
					bestCell = user.getUserAssets().getTile().getMap().getByXandY(w.getCell().getX() - 1, w.getCell().getY() - 1);
				}
			}
			
			
			w = w.getNext();
		}
		
		max = 0;
		return bestCell.getID();
	}
	
	private boolean checkIfMustDefend() {
		
		if (user.getUserAssets().getTowers().size() == 0) {
			return true;
		}
		
		for(UserAssets u : startAI.getLogic().getManager().getUserAssets().values()) {
			if(!u.getID().equals(user.getUserAssets().getID())) {
				for(Creep cr : u.getCreeps().values()) {
					float health = cr.getHealth();
					for(LinkedList<Cell> list: towerShotSorted.subList(cr.getCurrentWaypoint().getIndex(), towerShotSorted.size() - 1)) {
						for(Cell c : list) {
							if(c.getTower() != null) {
								float fireRate = 2000 / c.getTower().getTowerDescription().getCoolDownMax();
//								int creeps = u.getCreeps().size();
//								if (creeps == 0) {
//									creeps = 1;
//								}
								health -= c.getTower().getTowerDescription().getDamage() / fireRate;
							}
							if(health <= 0) {
								break;
							}
						}
						if(health <= 0) {
							break;
						}
					}
					if(health > 0) {
						System.out.println("Defend");
						return true;
					}
				}
			}
		}
		System.out.println("Recruit");
		return false;
	}
	
	private boolean isNeighbourOfWaypoint(Cell c) {
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY()).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY()).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 1).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 1).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() + 1).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() - 1).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() + 1).getType().equals("WALKABLE")) {
			return true;
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() - 1).getType().equals("WALKABLE")) {
			return true;
		}
		return false;
	}
	
	private String neighbourCell(String cellID) {
		Cell c = user.getUserAssets().getTile().getMap().getCell(cellID);
		Cell bestCell = null;
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY()).getTower() == null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY()).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY());
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY()).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY()).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY());
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 1).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 1).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 1);
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 1).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 1).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 1);
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() + 1).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() + 1).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() + 1);
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() - 1).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() - 1).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 1, c.getY() - 1);
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() + 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() + 1).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() + 1).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() + 1);
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() - 1) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() - 1).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() - 1).getType().equals("TOWER")) {
			bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 1, c.getY() - 1);
			if (isNeighbourOfWaypoint(bestCell)) {
				return bestCell.getID();
			}
		}
		
		if (bestCell == null) {
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY()).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY()).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY());
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY()) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY()).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY()).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY());
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 2) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 2).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 2).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() - 2);
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 2) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 2).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 2).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX(), c.getY() + 2);
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() + 2) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() + 2).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() + 2).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() + 2);
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() - 2) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() - 2).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() - 2).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() + 2, c.getY() - 2);
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() + 2) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() + 2).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() + 2).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() + 2);
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
			
			if (user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() - 2) != null && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() - 2).getTower() == null  && user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() - 2).getType().equals("TOWER")) {
				bestCell = user.getUserAssets().getTile().getMap().getByXandY(c.getX() - 2, c.getY() - 2);
				if (isNeighbourOfWaypoint(bestCell)) {
					return bestCell.getID();
				}
			}
		}
		
		return bestCell.getID();
	}
	
	private void sendOrUpgradeTowers() {
		int gold = user.getUserAssets().getBalance();
		
		if (gold >= 200 && !states[0]) {
			
			String cellID = findBestCell();
			JsonSender.createTower("Slow", cellID);
			waits(200);
			JsonSender.createTower("Basic", neighbourCell(cellID));
			waits(200);
			JsonSender.createTower("Basic", neighbourCell(cellID));
			states[0] = true;
			currentState = 1;
			
		} else if (gold >= 450 && states[0] && !states[1]) {
			
			String cell = "";
			
			for (Tower t : user.getUserAssets().getTowers().values()) {
				if (t.getTowerDescription().getName().equals("Basictower")) {
					waits(200);
					JsonSender.upgradeTower(t.getID(), "2");
				} else if(t.getTowerDescription().getName().equals("Slowtower")) {
					JsonSender.upgradeTower(t.getID(), "2");
					cell = t.getCell().getID();
					waits(200);
				}		
			}
			
			JsonSender.createTower("Basic", neighbourCell(cell));

			states[1] = true;
			currentState = 2;
			
		} else if(gold >= 100 && states[1] && !states[2]) {
			
			for (Tower t : user.getUserAssets().getTowers().values()) {
				if (t.getTowerDescription().getName().equals("Basictower") && t.getLevel() == 1) {
					JsonSender.upgradeTower(t.getID(), "2");	
				}
			}
			states[2] = true;
			currentState = 3;
			
		} else if (gold >= 1100 && states[2] && !states[3]) {
			
			String cellID = findBestCell();
			
			JsonSender.createTower("Speed", cellID);
			waits(1000);
			for (Tower t : user.getUserAssets().getTowers().values()) {
				if (t.getTowerDescription().getName().equals("Speedtower")) {
					JsonSender.createTower("Slow", neighbourCell(cellID));	
				}
			}
			
			states[3] = true;
			currentState = 4;
			
		} else if (gold >= 3200 && states[3] && !states[4]){
			
			String Speedtower = "";
			String Slowtower = "";
			
			for (Tower t : user.getUserAssets().getTowers().values()) {
				if (t.getTowerDescription().getName().equals("Speedtower")) {
					Speedtower = t.getID();
					speed = t.getID();
				} else if(t.getTowerDescription().getName().equals("Slowtower") && t.getLevel() == 1) {
					Slowtower = t.getID();
					slow = t.getID();
				}		
			}
			
			JsonSender.upgradeTower(Speedtower, "2");
			waits(200);
			JsonSender.upgradeTower(Slowtower, "2");
			states[4] = true;
			currentState = 5;
			
		} else if (gold >= 7900 && states[4] && !states[5]) {
			
			JsonSender.upgradeTower(speed, "3");
			waits(200);
			JsonSender.upgradeTower(slow, "3");
			states[5] = true;
			currentState = 6;
			
		} else if (gold >= 18000 && states[5]) {
			
			JsonSender.upgradeTower(speed, "4");
			waits(200);
			JsonSender.upgradeTower(slow, "4");
		} 
	}
	
	private String getBestCreep() {
		int income = user.getUserAssets().getIncome();
		int gold = user.getUserAssets().getBalance();
		
		if (income == 200 && gold >= 50) {
			return "Mercury";
		} else if (income > 200 && income < 400 && gold >= 100) {
			return "Mako";
		} else if (income >= 400 && income < 600 && gold >= 250) {
			return "FastNova";
		} else if(income >= 600 && income < 2000 && gold >= 500) {
			return "LargeManta";
		} else if(income >= 2000 && income < 4000 && gold >= 2000) {
			return "Ray";
		} else if(income >= 4000 && income < 8000 && gold >= 4000) {
			return "SpeedyRaider";
		} else if(income >= 8000 && income < 15000 && gold >= 8000) {
			return "BigToucan";
		} else if(income >= 15000 && income < 20000 && gold >= 15000) {
			return "Vulture";
		} else if(income >= 20000 && income < 35000 && gold >= 25000) {
			return "Shark";
		} else if(income >= 35000 && income < 50000 && gold >= 40000) {
			return "RacingMamba";
		}
		return "";
	}

//	private boolean saveMoney() {
//		int gold = user.getUserAssets().getBalance();
//		if (gold / stateInformation[currentState] >= 1) {
//			return false;
//		} else if (gold / stateInformation[currentState] > 0.75) {
//			return true;
//		} else {
//			return false;
//		}
//	}
	
	/**
	 * This method plays the game
	 */
	private void playGame() {
		//startAI.getConnection().getJsonHandler().getJsonSender().createCreep(getBestCreep());
		isRunning = true;
		cellToValue(); //-> Initiator.getPriorityCells(..)
		sortShotOrder(); //-> remove
		System.out.println(name + ": is ingame and is going to kill you");
		
		
		while(isRunning && startAI.getLogic().getGame().isRunning() && isGamePlaying() && startAI.getLogic().getGame().getWinner() == null) {
			System.out.println(name + ": plays the game");
			
			waits(10);
			
			//decide random, whether to build a tower or to send a creep
//			if (saveMoney()) {
//				//do nothing
//			} else 
				if(checkIfMustDefend()) {
				//decided to build a tower
				//startAI.getConnection().getJsonHandler().getJsonSender().createTower(getBestTower(), findBestCell());
				sendOrUpgradeTowers();
			} else {
				//decided to build a creep
				JsonSender.createCreep(getBestCreep());
			}
		}
	}
	
	/**
	 * Checks, if the game is still ongoing for the ai. 
	 * @return
	 */
	private boolean isGamePlaying() {
		for(UserAssets u: startAI.getLogic().getManager().getUserAssets().values()) {
			if(u.getUser() == user) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * This method waits for the requested time. 
	 * @param millis
	 */
	private void waits(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void close() {
		System.out.println(name + ": request to close");
		MapRepository.clear();
	}

	@Override
	public void addEvent(Event event) {
		System.out.println("Event: " + event.getKey() + " " + event.getValue());
		
		if(event.getKey().equals("closed")) {
			isRunning = false;
		} else if(event.getKey().equals("ErrorOccured")) {
			if(event.getValue().equals("Wrong paramter")) {
				if(loggedIn && !inGame) {
					System.out.println(name + ": has wrong game name. Program exit");
					System.exit(0);
				}
			}
		} else if(event.getKey().equals("login")) {
			if(event.getValue().equals("true")) {
				loggedIn = true;
			} else {
				System.out.println(name + ": wrong login parameters. Program exit. ");
				System.exit(0);
			}
		} else if(event.getKey().equals("running")) {
			gameStarted = true;
		} else if(event.getKey().equals("winner")) {
			isRunning = false;
		}
	}

	@Override
	public Nifty getNifty() {
		return null;
	}

	@Override
	public Screen getCurrentScreen() {
		return null;
	}

	@Override
	public LoadingScreen getLoadingScreen() {
		return null;
	}

	@Override
	public LoginScreen getLoginScreen() {
		return null;
	}

	@Override
	public LobbyScreen getLobbyScreen() {
		return null;
	}

	@Override
	public MapEditorScreen getMapEditorScreen() {
		return null;
	}

	@Override
	public IngameScreen getIngameScreen() {
		return null;
	}

	@Override
	public void setCurrentScreen(Screen currentScreen) {
		
	}

	public int getCurrentState() {
		return currentState;
	}
	
	public int[] getStateInformation() {
		return stateInformation;
	}

	@Override
	public void setFollowingScreen(Screen followingScreen) {
		// TODO Auto-generated method stub
		
	}
}
